home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / procssng / ccs / ccs-11tl.lha / lbl / xview / guidexv / gfm_load_dir.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-14  |  15.9 KB  |  679 lines

  1. /*
  2.  * This file is a product of Sun Microsystems, Inc. and is provided for
  3.  * unrestricted use provided that this legend is included on all tape
  4.  * media and as a part of the software program in whole or part.  Users
  5.  * may copy or modify this file without charge, but are not authorized to
  6.  * license or distribute it to anyone else except as part of a product
  7.  * or program developed by the user.
  8.  *
  9.  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  10.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  11.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  12.  *
  13.  * This file is provided with no support and without any obligation on the
  14.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  15.  * modification or enhancement.
  16.  *
  17.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  18.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE
  19.  * OR ANY PART THEREOF.
  20.  *
  21.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  22.  * or profits or other special, indirect and consequential damages, even
  23.  * if Sun has been advised of the possibility of such damages.
  24.  *
  25.  * Sun Microsystems, Inc.
  26.  * 2550 Garcia Avenue
  27.  * Mountain View, California  94043
  28.  */
  29.  
  30. #ifndef lint
  31. static char    sccsid[] = "@(#)gfm_load_dir.c    2.22 91/10/15 Copyright 1990 Sun Microsystems";
  32. #endif
  33.  
  34. #include <stdio.h>
  35. #include <dirent.h>
  36. #include <string.h>
  37. #include <malloc.h>
  38. #include <memory.h>
  39. #include <sys/param.h>
  40. #include <sys/types.h>
  41. #include <sys/stat.h>
  42. #include <sys/errno.h>
  43. #include <xview/xview.h>
  44. #include <xview/panel.h>
  45. #include <xview/textsw.h>
  46. #include <xview/svrimage.h>
  47. #include <xview/notify.h>
  48. #include <group.h>
  49. #include "gfm.h"
  50.  
  51. extern int    errno;
  52.  
  53. typedef struct {
  54.     char        *filename;
  55.     Xv_opaque    glyph;
  56.     GFM_TYPE    type;   /* To be used for client data in the list. */
  57. } GFM_LIST_ENTRY;
  58.  
  59. #define    STRCMP(s1, s2)    strcmp(s1 ? s1 : "", s2 ? s2 : "")
  60.  
  61. #define    GFM_LIST_INC    16
  62. static GFM_LIST_ENTRY    *Gfm_list;
  63. static int        Gfm_list_count;
  64. static int        Gfm_list_lth;
  65.  
  66. static void        list_add_entry();
  67. static void        list_batch_insert();
  68. static void        list_reset();
  69. static int        list_entry_cmp();
  70. static int        is_a_dir();
  71.  
  72. /*
  73.  * Define glyphs that we will use in the file list
  74.  */
  75. Server_image    Gfm_document_glyph;
  76. Server_image    Gfm_folder_glyph;
  77. Server_image    Gfm_dotdot_glyph;
  78. Server_image    Gfm_executable_glyph;
  79. Server_image    Gfm_broken_link_glyph;
  80. Server_image    Gfm_system_doc_glyph;
  81.  
  82. static unsigned short folder_bits[] =
  83. {
  84. #include "gfm_folder.pr"
  85. };
  86.  
  87. static unsigned short dotdot_bits[] =
  88. {
  89. #include "gfm_dotdot.pr"
  90. };
  91.  
  92. static unsigned short document_bits[] =
  93. {
  94. #include "gfm_data.pr"
  95. };
  96.  
  97. static unsigned short executable_bits[] =
  98. {
  99. #include "gfm_app.pr"
  100. };
  101.  
  102. static unsigned short broken_link_bits[] =
  103. {
  104. #include "gfm_unknown.pr"
  105. };
  106.  
  107. static unsigned short system_doc_bits[] =
  108. {
  109. #include "gfm_system.pr"
  110. };
  111.  
  112. /*
  113.  * Initialize all glyphs used in the scrolling list
  114.  */
  115. void
  116. gfm_initialize_glyphs()
  117. {
  118.     if (Gfm_folder_glyph)
  119.         return;
  120.  
  121.     Gfm_folder_glyph = (Server_image) xv_create(NULL, SERVER_IMAGE,
  122.         XV_WIDTH,     16,
  123.         XV_HEIGHT,     16,
  124.         SERVER_IMAGE_BITS,     folder_bits,
  125.         NULL);
  126.  
  127.     Gfm_dotdot_glyph = (Server_image) xv_create(NULL, SERVER_IMAGE,
  128.         XV_WIDTH,     16,
  129.         XV_HEIGHT,     16,
  130.         SERVER_IMAGE_BITS,     dotdot_bits,
  131.         NULL);
  132.  
  133.     Gfm_executable_glyph = (Server_image) xv_create(NULL, SERVER_IMAGE,
  134.         XV_WIDTH,     16,
  135.         XV_HEIGHT,     16,
  136.         SERVER_IMAGE_BITS,     executable_bits,
  137.         NULL);
  138.  
  139.     Gfm_document_glyph = (Server_image) xv_create(NULL, SERVER_IMAGE,
  140.         XV_WIDTH,     16,
  141.         XV_HEIGHT,     16,
  142.         SERVER_IMAGE_BITS,     document_bits,
  143.         NULL);
  144.  
  145.     Gfm_broken_link_glyph = (Server_image) xv_create(NULL, SERVER_IMAGE,
  146.         XV_WIDTH,     16,
  147.         XV_HEIGHT,     16,
  148.         SERVER_IMAGE_BITS,     broken_link_bits,
  149.         NULL);
  150.  
  151.     Gfm_system_doc_glyph = (Server_image) xv_create(NULL, SERVER_IMAGE,
  152.         XV_WIDTH,     16,
  153.         XV_HEIGHT,     16,
  154.         SERVER_IMAGE_BITS,     system_doc_bits,
  155.         NULL);
  156. }
  157.  
  158. /*
  159.  * gfm_load_dir
  160.  *
  161.  * The workhorse of this program.  It loads the directory into a newly
  162.  * created PANEL_LIST.
  163.  */
  164. void
  165. #ifdef __STDC__
  166. gfm_load_dir(gfm_popup_objects *ip, char *dir)
  167. #else
  168. gfm_load_dir(ip, dir)
  169.     gfm_popup_objects    *ip;
  170.     char            *dir;
  171. #endif
  172. {
  173.     /* Directory stuff */
  174.     DIR        *dirp;
  175.     struct dirent    *dp;
  176.     struct stat    buf;
  177.     int        l;
  178.     int        matched;
  179.     int        chunk_len;
  180.     char        *s;
  181.     char        *chunk_start = NULL;
  182.     char        *chunk_stop = NULL;
  183.     char        *path_rest = NULL;
  184.     char        *path_end = NULL;
  185.     char        new_dir[MAXPATHLEN + 1];
  186.     char        path_prefix[MAXPATHLEN + 1];
  187.     char        sym_link[MAXPATHLEN + 1];
  188.     char        *current_dir;
  189.     GFM_PRIVATE    *gfm_private;
  190.  
  191.     memset(new_dir, '\0', sizeof(new_dir));
  192.     memset(path_prefix, '\0', sizeof(path_prefix));
  193.  
  194.     xv_set(ip->popup, FRAME_BUSY, TRUE, NULL);
  195.     gfm_private = (GFM_PRIVATE *) xv_get(ip->popup, XV_KEY_DATA, GFM_KEY);
  196.     current_dir = (char *)xv_get(ip->directory, PANEL_VALUE);
  197.  
  198.     /*
  199.      * Check to see if new directory is absolute or relative
  200.      */
  201.     expand_path(dir, new_dir);
  202.     path_rest = new_dir;
  203.  
  204.     /*
  205.      * Remove trailing "/" that expand path might add on
  206.      */
  207.     if (((l = strlen(new_dir) - 1) > 1) && (new_dir[l] == '/'))
  208.         new_dir[l] = '\0';
  209.  
  210.     if (*new_dir == '/')
  211.         strcpy(path_prefix, "");
  212.     else
  213.         strcpy(path_prefix, current_dir);
  214.  
  215.     /*
  216.      * Incrementally add directory segments
  217.      */
  218.     for (chunk_start = new_dir;
  219.          chunk_start <= (new_dir + strlen(new_dir));
  220.          chunk_start = path_rest = chunk_stop + 1) {
  221.  
  222.         if (!(chunk_stop = strchr(path_rest, '/'))) {
  223.             chunk_stop = path_rest + strlen(path_rest);
  224.         } else if (chunk_stop == path_rest)
  225.             continue;
  226.  
  227.         chunk_len = chunk_stop - chunk_start;
  228.  
  229.         /* Ignore embedded "." and "/" */
  230.         if ((strncmp(chunk_start, ".", chunk_len) == 0) ||
  231.             (strncmp(chunk_start, "/", chunk_len) == 0))
  232.             continue;
  233.  
  234.         /* Remove one directory from path */
  235.         if (strncmp(chunk_start, "..", chunk_len) == 0) {
  236.             if (s = strrchr(path_prefix, '/'))
  237.                 *s = '\0';
  238.             continue;
  239.         }
  240.  
  241.         l = strlen(path_prefix);
  242.         path_end = path_prefix + l;
  243.         if ((l == 0) || (path_prefix[l - 1] != '/'))
  244.             strcat(path_prefix, "/");
  245.         strncat(path_prefix, chunk_start, chunk_len);
  246.  
  247.         if (!is_a_dir(path_prefix)) {
  248.             *path_end = '\0';
  249.             break;
  250.         }
  251.     }
  252.  
  253.     if (strcmp(path_prefix, "") == 0)
  254.         strcat(path_prefix, "/");
  255.  
  256.     if (!path_rest || !*path_rest || path_rest > (new_dir + strlen(new_dir)))
  257.         path_rest = NULL;
  258.  
  259.     /*
  260.      * If there were any remaining portions, put them in the file
  261.      * field.  If it contained a /, beep.
  262.      * XXX - In V3 we should select this but we can't because the
  263.      * window must have focus for the select to take effect.
  264.      */
  265.     if (path_rest && *path_rest) {
  266.         if (strchr(path_rest, '/'))
  267.             xv_set(ip->popup, WIN_ALARM, NULL);
  268.         xv_set(ip->file, PANEL_VALUE, path_rest, NULL);
  269.     } else
  270.         xv_set(ip->file, PANEL_VALUE, "", NULL);
  271.  
  272.     if (stat(path_prefix, &buf) < 0)
  273.     {
  274.         fprintf(stderr,
  275.             dgettext("libguidexv",
  276.                      "gfm: Could not \"stat\" directory %s\n"),
  277.             path_prefix);
  278.         xv_set(ip->popup, FRAME_BUSY, FALSE, NULL);
  279.         return;
  280.     }
  281.  
  282.     /*
  283.      * Return if we are loading the same directory and the directory
  284.      * hasn't been modified.
  285.      */
  286.     if (current_dir && *current_dir &&
  287.         (strcmp(path_prefix, current_dir) == 0) &&
  288.         (buf.st_mtime == gfm_private->dir_mtime)) {
  289.         xv_set(ip->popup, FRAME_BUSY, FALSE, NULL);
  290.         return;
  291.     }
  292.  
  293.     gfm_private->dir_mtime = buf.st_mtime;
  294.  
  295.     /*
  296.      * Open the directory for reading, then set the directory field
  297.      */
  298.     if ((dirp = opendir(path_prefix)) == NULL)
  299.     {
  300.         fprintf(stderr, dgettext("libguidexv",
  301.                      "gfm: Could not open directory %s\n"),
  302.             path_prefix);
  303.         xv_set(ip->popup, FRAME_BUSY, FALSE, NULL);
  304.         return;
  305.     }
  306.     xv_set(ip->directory, PANEL_VALUE, path_prefix, NULL);
  307.  
  308.     /*
  309.      * Set up up path prefix since we don't * do a chdir().  All our
  310.      * stats will need to be absolute...
  311.      */
  312.     if (path_prefix[strlen(path_prefix) - 1] != '/') {
  313.         strcat(path_prefix, "/");
  314.     }
  315.     path_end = path_prefix + strlen(path_prefix);
  316.  
  317.     if (gfm_private->filter_pattern)
  318.         gfm_compile_regex(gfm_private->filter_pattern);
  319.  
  320.     while (dp = readdir(dirp)) {
  321.         if (strcmp(dp->d_name, "..") == 0) {
  322.             list_add_entry(ip, gfm_private,
  323.                        GFM_DOTDOT_STR, GFM_FOLDER);
  324.             continue;
  325.         }
  326.  
  327.         /* Don't add '.' */
  328.         if (strcmp(dp->d_name, ".") == 0)
  329.             continue;
  330.  
  331.         if (!gfm_private->show_dotfiles && (*(dp->d_name) == '.'))
  332.             continue;
  333.  
  334.         strcpy(path_end, dp->d_name);
  335.  
  336.         /* Error!! */
  337.         if (stat(path_prefix, &buf) < 0) {
  338.             if (errno == ENOENT)
  339.                 list_add_entry(ip, gfm_private,
  340.                            dp->d_name, GFM_BROKENLINK);
  341.             continue;
  342.         }
  343.  
  344.         if ((buf.st_mode & S_IFMT) == S_IFDIR) {
  345.             list_add_entry(ip, gfm_private, dp->d_name, GFM_FOLDER);
  346.             continue;
  347.         }
  348.  
  349.         if (gfm_private->filter_pattern)
  350.             matched = gfm_match_regex(path_end);
  351.         else
  352.             matched = TRUE;
  353.  
  354.         if (gfm_private->filter_callback) {
  355.             if (gfm_private->filter_callback(ip, path_prefix) && matched)
  356.                 list_add_entry(ip, gfm_private,
  357.                            dp->d_name, GFM_USERDEF);
  358.             continue;
  359.         } else if (gfm_private->filter_pattern) {
  360.             if (matched)
  361.                 list_add_entry(ip, gfm_private,
  362.                            dp->d_name, GFM_USERDEF);
  363.             continue;
  364.         }
  365.  
  366.         /*
  367.          * We can't just and the mode with S_IFMT
  368.          * because executable permissions are in a different
  369.          * group of bits.  We shift the mask to also
  370.          * take the cases of only owner, group or others
  371.          * have permission to execute.
  372.          */
  373.         if (strcmp(dp->d_name, "core") == 0) {
  374.             list_add_entry(ip, gfm_private,
  375.                        dp->d_name, GFM_SYSDOC);
  376.             continue;
  377.         }
  378.  
  379.         if (buf.st_mode & S_IEXEC) {
  380.             list_add_entry(ip, gfm_private,
  381.                        dp->d_name, GFM_APPLICATION);
  382.             continue;
  383.         }
  384.  
  385.         switch (buf.st_mode & S_IFMT) {
  386.         case S_IFREG:
  387.             list_add_entry(ip, gfm_private,
  388.                        dp->d_name, GFM_DOCUMENT);
  389.             break;
  390.         case S_IFDIR:
  391.             list_add_entry(ip, gfm_private,
  392.                        dp->d_name, GFM_FOLDER);
  393.             break;
  394.         case S_IFCHR:
  395.         case S_IFIFO:
  396.         case S_IFBLK:
  397.         case S_IFSOCK:
  398.             list_add_entry(ip, gfm_private,
  399.                        dp->d_name, GFM_SYSDOC);
  400.             break;
  401.         case S_IFLNK:
  402.             if ((l = readlink(dp->d_name, sym_link, sizeof (sym_link))) > 0) {
  403.                 sym_link[l] = '\0';
  404.                 if (stat(sym_link, &buf) < 0) {
  405.                     /* Error.  Broken link. */
  406.                     list_add_entry(ip, gfm_private,
  407.                                dp->d_name, GFM_BROKENLINK);
  408.                     continue;
  409.                 }
  410.                 if (buf.st_mode & (S_IEXEC | (S_IEXEC>>1) | (S_IEXEC>>2))) {
  411.                     list_add_entry(ip, gfm_private,
  412.                                dp->d_name, GFM_APPLICATION);
  413.                     continue;
  414.                 }
  415.                 switch (buf.st_mode & S_IFMT) {
  416.                 case S_IEXEC:
  417.                     list_add_entry(ip, gfm_private,
  418.                                dp->d_name, GFM_APPLICATION);
  419.                     break;
  420.                 case S_IFREG:
  421.                     list_add_entry(ip, gfm_private,
  422.                                dp->d_name, GFM_DOCUMENT);
  423.                     break;
  424.                 case S_IFDIR:
  425.                     list_add_entry(ip, gfm_private,
  426.                                dp->d_name, GFM_FOLDER);
  427.                     break;
  428.                 case S_IFCHR:
  429.                 case S_IFIFO:
  430.                 case S_IFBLK:
  431.                 case S_IFSOCK:
  432.                 case S_IFLNK:
  433.                     list_add_entry(ip, gfm_private,
  434.                                dp->d_name, GFM_SYSDOC);
  435.                     break;
  436.                 default:
  437.                     list_add_entry(ip, gfm_private,
  438.                                dp->d_name, GFM_BROKENLINK);
  439.                 }
  440.             }
  441.             break;
  442.         default:
  443.             break;
  444.         }
  445.     }
  446.  
  447.     closedir(dirp);
  448.  
  449.     /*
  450.      * Sort the list, start sorting at the second position so that ".."
  451.      * is always at the top.
  452.      */
  453.     qsort((char *)&Gfm_list[1], Gfm_list_count-1, sizeof (GFM_LIST_ENTRY), list_entry_cmp);
  454.  
  455.     list_batch_insert(ip, gfm_private);
  456.     list_reset(ip, gfm_private);
  457.     xv_set(ip->popup, FRAME_BUSY, FALSE, NULL);
  458. }
  459.  
  460. /*
  461.  * Comparison routine for quicksort of list entries in Gfm_list
  462.  */
  463. static int
  464. #ifdef __STDC__
  465. list_entry_cmp(GFM_LIST_ENTRY *entry1, GFM_LIST_ENTRY *entry2)
  466. #else
  467. list_entry_cmp(entry1, entry2)
  468.     GFM_LIST_ENTRY    *entry1;
  469.     GFM_LIST_ENTRY    *entry2;
  470. #endif
  471. {
  472.     return STRCMP(entry1->filename, entry2->filename);
  473. }
  474.  
  475. /*
  476.  * Add and entry to the list
  477.  */
  478. /*ARGSUSED*/
  479. static void
  480. #ifdef __STDC__
  481. list_add_entry(gfm_popup_objects *ip, GFM_PRIVATE *gfm_private,
  482.            char *name, GFM_TYPE type)
  483. #else
  484. list_add_entry(ip, gfm_private, name, type)
  485.     gfm_popup_objects *ip;
  486.     GFM_PRIVATE      *gfm_private;
  487.     char          *name;
  488.     GFM_TYPE      type;
  489. #endif
  490. {
  491.     if (Gfm_list_count == Gfm_list_lth)
  492.     {
  493.         if (Gfm_list)
  494.             Gfm_list = (GFM_LIST_ENTRY *)
  495.                 realloc(Gfm_list,
  496.                     (Gfm_list_lth += GFM_LIST_INC) *
  497.                     sizeof (GFM_LIST_ENTRY));
  498.         else
  499.             Gfm_list = (GFM_LIST_ENTRY *)
  500.                 malloc((Gfm_list_lth += GFM_LIST_INC) *
  501.                        sizeof(GFM_LIST_ENTRY));
  502.     }
  503.  
  504.     Gfm_list[Gfm_list_count].filename = strdup(name);
  505.     Gfm_list[Gfm_list_count].type = type;
  506.  
  507.     switch (type) {
  508.     case GFM_FOLDER:
  509.         if (strcmp(name, (char *)GFM_DOTDOT_STR) == 0)
  510.             Gfm_list[Gfm_list_count].glyph = Gfm_dotdot_glyph;
  511.         else
  512.             Gfm_list[Gfm_list_count].glyph = Gfm_folder_glyph;
  513.         break;
  514.     case GFM_APPLICATION:
  515.         Gfm_list[Gfm_list_count].glyph = Gfm_executable_glyph;
  516.         break;
  517.     case GFM_BROKENLINK:
  518.         Gfm_list[Gfm_list_count].glyph = Gfm_broken_link_glyph;
  519.         break;
  520.     case GFM_DOCUMENT:
  521.         Gfm_list[Gfm_list_count].glyph = Gfm_document_glyph;
  522.         break;
  523.     case GFM_USERDEF:
  524.         Gfm_list[Gfm_list_count].glyph = gfm_private->user_glyph;
  525.         break;
  526.     case GFM_SYSDOC:
  527.         Gfm_list[Gfm_list_count].glyph = Gfm_system_doc_glyph;
  528.         break;
  529.     default:
  530.         Gfm_list[Gfm_list_count].glyph = NULL;
  531.         Gfm_list[Gfm_list_count].type = GFM_BROKENLINK;
  532.     }
  533.  
  534.     Gfm_list_count++;
  535. }
  536.  
  537. /*
  538.  * Empty current list of all it's contents
  539.  */
  540. /*ARGSUSED*/
  541. static void
  542. #ifdef __STDC__
  543. empty_list(gfm_popup_objects *ip, GFM_PRIVATE *gfm_private)
  544. #else
  545. empty_list(ip, gfm_private)
  546.     gfm_popup_objects    *ip;
  547.     GFM_PRIVATE        *gfm_private;
  548. #endif
  549. {
  550.     int        width;
  551.     int        nrows;
  552.     Xv_opaque    old_list;
  553.  
  554.     /*
  555.      * Destroy old list (faster than deleting all entries at the moment)
  556.      * then recreate it.  Note, we must hide it first to get around
  557.      * XView bugid 1042729.
  558.      */
  559.     old_list = ip->list;
  560.     width = (int)xv_get(ip->list, PANEL_LIST_WIDTH);
  561.     nrows = (int)xv_get(ip->list, PANEL_LIST_DISPLAY_ROWS);
  562.     xv_set(ip->list, XV_SHOW, FALSE, NULL);
  563.     xv_destroy_safe(ip->list);
  564.     ip->list = gfm_popup_list_create(ip, ip->controls);
  565.  
  566.     xv_set(ip->list,
  567.         PANEL_LIST_WIDTH, width,
  568.         PANEL_LIST_DISPLAY_ROWS, nrows,
  569.         NULL);
  570.  
  571.     /*
  572.      * Make sure to tell the GROUP pkg that we have replaced the
  573.      * list with a new one.
  574.      */
  575.     xv_set(ip->file_list_group,
  576.         GROUP_REPLACE_MEMBER, old_list, ip->list,
  577.         NULL);
  578. }
  579.  
  580. /*
  581.  * Reset internal list.
  582.  *    N.B. Space for list array is not freed, kept around for next time
  583.  */
  584. /*ARGSUSED*/
  585. static void
  586. #ifdef __STDC__
  587. list_reset(gfm_popup_objects *ip, GFM_PRIVATE *gfm_private)
  588. #else
  589. list_reset(ip, gfm_private)
  590.     gfm_popup_objects    *ip;
  591.     GFM_PRIVATE        *gfm_private;
  592. #endif
  593. {
  594.     int    i;
  595.  
  596.     for (i = 0; i < Gfm_list_count; i++)
  597.         free(Gfm_list[i].filename);
  598.     Gfm_list_count = 0;
  599. }
  600.  
  601. /*
  602.  * Insert internal list into scrolling list in chunks.
  603.  */
  604. static void
  605. #ifdef __STDC__
  606. list_batch_insert(gfm_popup_objects *ip, GFM_PRIVATE *gfm_private)
  607. #else
  608. list_batch_insert(ip, gfm_private)
  609.     gfm_popup_objects    *ip;
  610.     GFM_PRIVATE        *gfm_private;
  611. #endif
  612. {
  613.     int    i = 0;
  614.     void    *attr_array[ATTR_STANDARD_SIZE];
  615.     void    **attr_ptr;
  616.     void    **attr_end;
  617.  
  618.     empty_list(ip, gfm_private);
  619.     xv_set(ip->list, XV_SHOW, FALSE, NULL);
  620.  
  621.     attr_ptr = attr_array;
  622.     attr_end = &attr_array[ATTR_STANDARD_SIZE - 20];
  623.  
  624.     for (i = 0; i < Gfm_list_count; i++) {
  625.         *attr_ptr++ = (void *) PANEL_LIST_INSERT;
  626.         *attr_ptr++ = (void *) i;
  627.  
  628.         *attr_ptr++ = (void *) PANEL_LIST_STRING;
  629.         *attr_ptr++ = (void *) i;
  630.         *attr_ptr++ = (void *) Gfm_list[i].filename;
  631.  
  632.         *attr_ptr++ = (void *) PANEL_LIST_GLYPH;
  633.         *attr_ptr++ = (void *) i;
  634.         *attr_ptr++ = (void *) Gfm_list[i].glyph;
  635.  
  636.         *attr_ptr++ = (void *) PANEL_LIST_CLIENT_DATA;
  637.         *attr_ptr++ = (void *) i;
  638.         *attr_ptr++ = (void *) (Gfm_list[i].type | (i << 3));
  639.  
  640.         /*
  641.          * Check for overflow or completion, if full terminate
  642.          * the ATTR_LIST and set it on the scrolling list.
  643.          */
  644.         if (attr_ptr >= attr_end || i >= Gfm_list_count - 1) {
  645.             *attr_ptr = (void *) 0;
  646.             xv_set(ip->list, ATTR_LIST, attr_array, NULL);
  647.             attr_ptr = attr_array;
  648.         }
  649.     }
  650.  
  651.     /*
  652.      * Select first item and make list visible
  653.      */
  654.     xv_set(ip->list,
  655.            PANEL_LIST_SELECT, 0,    TRUE,
  656.            PANEL_CLIENT_DATA,    GFM_FOLDER,
  657.            XV_SHOW,        TRUE,
  658.            NULL);
  659. }
  660.  
  661. /*
  662.  * Is path name really a directory
  663.  */
  664. static int
  665. #ifdef __STDC__
  666. is_a_dir(char *path)
  667. #else
  668. is_a_dir(path)
  669.     char    *path;
  670. #endif
  671. {
  672.     struct stat    buf;
  673.  
  674.     if ((stat(path, &buf) < 0) || !((buf.st_mode & S_IFMT) == S_IFDIR))
  675.         return FALSE;
  676.     else
  677.         return TRUE;
  678. }
  679.